const path = require('path')
const FS = require('fs');
const Rollup = require('rollup');
const UglifyJS = require("uglify-js");
const CleanCSS = require("clean-css");

const _PATH_TO_INPUT_ROOT = `${__dirname}/`;
const _PATH_TO_OUTPUT_ROOT = `${_PATH_TO_INPUT_ROOT}../content/www/`;
console.log(`input root path:${_PATH_TO_INPUT_ROOT}`);
console.log(`output root path:${_PATH_TO_OUTPUT_ROOT}`);

const _PATH_TO_INPUT_JS_ROOT = `${_PATH_TO_INPUT_ROOT}js/`;
const _PATH_TO_OUTPUT_JS_ROOT = `${_PATH_TO_OUTPUT_ROOT}js/`;
const _INPUT_FILE_NAME = "index.js"
const _OUTPUT_BUNDLE_FILE_NAME = "index.bundle.js"
const _OUTPUT_MINI_FILE_NAME = "index.bundle.min.js"

const _PATH_TO_INPUT_CSS_ROOT = `${_PATH_TO_INPUT_ROOT}css/`;
const _PATH_TO_OUTPUT_CSS_ROOT = `${_PATH_TO_OUTPUT_ROOT}css/`;
const _INPUT_CSS_FILE_NAME = "style.css"
const _OUTPUT_CSS_FILE_NAME = "style.min.css"


const inputOptions = {
    // core input options
    ///external,
    input: path.resolve(_PATH_TO_INPUT_JS_ROOT, _INPUT_FILE_NAME),
    /// plugins,

    // advanced input options
    /// cache,
    /// onwarn,
    /// preserveEntrySignatures,
    /// strictDeprecations,

    // danger zone
    /// acorn,
    /// acornInjectPlugins,
    /// context,
    /// moduleContext,
    /// preserveSymlinks,
    /// shimMissingExports,
    /// treeshake,

    // experimental
    /// experimentalCacheExpiry,
    /// perf
};
const outputOptions = {
    // core output options
    /// dir,
    file: path.resolve(_PATH_TO_OUTPUT_JS_ROOT, _OUTPUT_BUNDLE_FILE_NAME),
    format: 'esm',
    /// globals,
    /// name,
    /// plugins,

    // advanced output options
    /// assetFileNames,
    /// banner,
    /// chunkFileNames,
    /// compact,
    /// entryFileNames,
    /// extend,
    /// externalLiveBindings,
    /// footer,
    /// hoistTransitiveImports,
    /// inlineDynamicImports,
    /// interop,
    /// intro,
    /// manualChunks,
    /// minifyInternalExports,
    /// outro,
    /// paths,
    /// preserveModules,
    /// preserveModulesRoot,
    /// sourcemap,
    /// sourcemapExcludeSources,
    /// sourcemapFile,
    /// sourcemapPathTransform,
    /// validate,

    // danger zone
    /// amd,
    /// esModule,
    /// exports,
    /// freeze,
    /// indent,
    /// namespaceToStringTag,
    /// noConflict,
    /// preferConst,
    /// sanitizeFileName,
    /// strict,
    /// systemNullSetters
};

async function Bundle() {
    console.info(new Date().toString(), 'Bundling...');
    // create a bundle
    const bundle = await Rollup.rollup(inputOptions);

    //console.log(bundle.watchFiles); // an array of file names this bundle depends on

    // generate output specific code in-memory
    // you can call this function multiple times on the same bundle object
    const {output} = await bundle.generate(outputOptions);

    for(const chunkOrAsset of output) {
        if(chunkOrAsset.type === 'asset') {
            // For assets, this contains
            // {
            //   fileName: string,              // the asset file name
            //   source: string | Uint8Array    // the asset source
            //   type: 'asset'                  // signifies that this is an asset
            // }
            //console.log('Asset', chunkOrAsset);
        } else {
            // For chunks, this contains
            // {
            //   code: string,                  // the generated JS code
            //   dynamicImports: string[],      // external modules imported dynamically by the chunk
            //   exports: string[],             // exported variable names
            //   facadeModuleId: string | null, // the id of a module that this chunk corresponds to
            //   fileName: string,              // the chunk file name
            //   implicitlyLoadedBefore: string[]; // entries that should only be loaded after this chunk
            //   imports: string[],             // external modules imported statically by the chunk
            //   importedBindings: {[imported: string]: string[]} // imported bindings per dependency
            //   isDynamicEntry: boolean,       // is this chunk a dynamic entry point
            //   isEntry: boolean,              // is this chunk a static entry point
            //   isImplicitEntry: boolean,      // should this chunk only be loaded after other chunks
            //   map: string | null,            // sourcemaps if present
            //   modules: {                     // information about the modules in this chunk
            //     [id: string]: {
            //       renderedExports: string[]; // exported variable names that were included
            //       removedExports: string[];  // exported variable names that were removed
            //       renderedLength: number;    // the length of the remaining code in this module
            //       originalLength: number;    // the original length of the code in this module
            //       code: string | null;       // remaining code in this module
            //     };
            //   },
            //   name: string                   // the name of this chunk as used in naming patterns
            //   referencedFiles: string[]      // files referenced via import.meta.ROLLUP_FILE_URL_<id>
            //   type: 'chunk',                 // signifies that this is a chunk
            // }
            //console.log('Chunk', chunkOrAsset.modules);
        }
    }

    // or write the bundle to disk
    await bundle.write(outputOptions);

    // closes the bundle
    await bundle.close();
    return Promise.resolve();
}

async function Uglify() {
    console.info(new Date().toString(), 'UglifyingJS...');
    const _fileContent = FS.readFileSync(path.resolve(_PATH_TO_OUTPUT_JS_ROOT, _OUTPUT_BUNDLE_FILE_NAME), "utf8")
    var options = {
        toplevel: true,
        compress: {
            global_defs: {
                //"@console.log": "alert"
            },
            passes: 2
        },
        output: {
            beautify: false,
            preamble: "/* uglified */"
        }
    };
    //var result = UglifyJS.minify(_fileContent, options);
    var result = UglifyJS.minify(_fileContent);
    //console.log(result);
    FS.mkdirSync(_PATH_TO_OUTPUT_JS_ROOT, {recursive: true});
    FS.writeFileSync(path.resolve(_PATH_TO_OUTPUT_JS_ROOT, _OUTPUT_MINI_FILE_NAME), result.code);
    return Promise.resolve();
}

async function UglifyCSS() {
    console.info(new Date().toString(), 'UglifyingCSS...');
    const _fileContent = FS.readFileSync(path.resolve(_PATH_TO_INPUT_CSS_ROOT, _INPUT_CSS_FILE_NAME), "utf8")
    const result = new CleanCSS().minify(_fileContent);
    //console.log(result);
    FS.mkdirSync(_PATH_TO_OUTPUT_CSS_ROOT, {recursive: true});
    FS.writeFileSync(path.resolve(_PATH_TO_OUTPUT_CSS_ROOT, _OUTPUT_CSS_FILE_NAME), result.styles);
    return Promise.resolve();
}

async function CopyFiles() {
    FS.cp(`${_PATH_TO_INPUT_ROOT}index.html`, `${_PATH_TO_OUTPUT_ROOT}index.html`, {force: true}, () => {});

    FS.mkdirSync(`${_PATH_TO_OUTPUT_JS_ROOT}languages/`, {recursive: true});
    FS.cp(`${_PATH_TO_INPUT_ROOT}3rd/highlight.js/es/languages/`, `${_PATH_TO_OUTPUT_JS_ROOT}languages/`, {force: true, recursive: true}, () => {});
    FS.cp(`${_PATH_TO_INPUT_ROOT}3rd/bootstrap/bootstrap.bundle.min.js`, `${_PATH_TO_OUTPUT_JS_ROOT}bootstrap.bundle.min.js`, {force: true, recursive: true}, () => {});

    FS.mkdirSync(`${_PATH_TO_OUTPUT_CSS_ROOT}bootstrap/`, {recursive: true});
    FS.cp(`${_PATH_TO_INPUT_CSS_ROOT}bootstrap/`, `${_PATH_TO_OUTPUT_CSS_ROOT}bootstrap/`, {force: true, recursive: true}, () => {});

    FS.mkdirSync(`${_PATH_TO_OUTPUT_CSS_ROOT}katex/`, {recursive: true});
    FS.cp(`${_PATH_TO_INPUT_CSS_ROOT}katex/`, `${_PATH_TO_OUTPUT_CSS_ROOT}katex/`, {force: true, recursive: true}, () => {});

    FS.mkdirSync(`${_PATH_TO_OUTPUT_CSS_ROOT}highlight.js/`, {recursive: true});
    FS.cp(`${_PATH_TO_INPUT_CSS_ROOT}highlight.js/`, `${_PATH_TO_OUTPUT_CSS_ROOT}highlight.js/`, {force: true, recursive: true}, () => {});
}

Bundle().then(Uglify).then(UglifyCSS).then(CopyFiles);


